# -*- coding:utf-8 -*-
"""
@Time:  2024/6/15 16:41
@Auth:  Mrs.Gou 
@Function:  装饰器：本质还是函数的应用
"""
import functools
import time

"""
函数：函数是组织好的，可重复使用的，用来实现功能的代码段函数是编程的最小功能单元
装饰器：装饰器，顾名思义，就是装饰（函数）的，用来增强（函数）的功能
形式：装饰器 @xxx()
"""


# 装饰器最多3层
# 两层装饰器使用的时候，一定不能带括号@my_time。三层装饰器，使用的时候一定要带括号@my_time()
def my_time_new(t='ms'):
    """最外层接收装饰器本身的参数"""

    def outer(func):
        # 这里的func其实就是my_func1这个被装饰函数
        """
        装饰器模板，并没有实现功能
        :param func: 是被装饰函数本身
        :return:
        """

        # 说明是被装饰函数本身（这里的name就是my_func1)
        # print(func.__name__)

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 这是一个内函数wrapper
            # 语法糖，作用2：把my_func1函数被调用时的实际传参，作为my_time内函数wrapper的参数传入。
            # 使用*args, **kwargs接收到的所有参数，然后在调用被装饰函数的时候，再*args, **kwargs原样传过去

            # 函数执行前
            t1 = time.time()
            print('my_time_new前')
            res = func(*args, **kwargs)

            # 函数执行后
            t2 = time.time()
            if t == 'ms':
                de_t = round((t2 - t1) * 1000, 2)
            elif t == 'μs':
                de_t = round((t2 - t1) * 1000000, 2)
            else:
                de_t = round(t2 - t1, 2)
            print('函数{}的执行耗时：{} {}'.format(func.__name__, de_t, t))
            print(f'函数{func.__name__}的执行耗时：{de_t} {t}')
            print('函数%s的执行耗时：%.2f %s ' % (func.__name__, de_t, t))
            # 这里应该return被装饰函数的返回值
            return res

        # 注意，装饰器内函数调用的时候，不要加括号
        return wrapper

    return outer


def my_time(func):
    # 这里的func其实就是my_func1这个被装饰函数
    """
    装饰器模板，并没有实现功能
    :param func: 是被装饰函数本身
    :return:
    """

    # 说明是被装饰函数本身（这里的name就是my_func1)
    # print(func.__name__)

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 这是一个内函数wrapper
        # 语法糖，作用2：把my_func1函数被调用时的实际传参，作为my_time内函数wrapper的参数传入。
        # 使用*args, **kwargs接收到的所有参数，然后在调用被装饰函数的时候，再*args, **kwargs原样传过去

        # 函数执行前
        t1 = time.time()
        print('my_time前')
        res = func(*args, **kwargs)

        # 函数执行后
        print('函数', func.__name__, '执行耗时', time.time() - t1)
        # 这里应该return被装饰函数的返回值
        return res

    # 注意，装饰器内函数调用的时候，不要加括号
    return wrapper


@my_time
@my_time_new()
# 语法糖，作用1：当我们在my_func1函数上面使用@my_time,我们会把my_func1函数作为my_time函数的参数传入
def my_func1(x, y, z=1):
    """这是文档说明"""
    time.sleep(0.5)
    print('这是func1', x, y)
    time.sleep(0.1)
    return 'will'


if __name__ == '__main__':
    # 只有右键run当前这个py的时候，才会执行这里的代码
    # 可以作为测试代码
    # 使用@functools.wraps(func)，让装饰器不改变原函数的属性
    # print(my_func1.__name__)
    # print(my_func1.__doc__)
    # 备注：哪些代码在导入的时候就会跑呢？这种顶格写，没有用函数或者类封装的代码
    z = my_func1(1, 2, 3)
    print(z)
